package com.ticket.common.utils.wechat;

import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * Description:
 *
 * @author: yuanjianpeng
 * @date: 2019-04-15 11:19
 */
public class WeixinUtil {

    private static Logger logger = LoggerFactory.getLogger(WeixinUtil.class);

    private static String access_token = null;
    private static String time = null;
    private static String jsapi_ticket = null;
    private static String customer_info = null;

    /**
     * 获取接口访问凭证
     *
     * @param appid
     *            凭证
     * @param appsecret
     *            密钥
     */
    private static String getAccess_token(String appid, String appsecret) {
        // 凭证获取(GET)
        String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
        // 发起GET请求获取凭证
        JSONObject jsonObject = httpsRequest(requestUrl);
        String access_token = null;
        if (null != jsonObject) {
            try {
                logger.info(jsonObject.toString());
                access_token = jsonObject.getString("access_token");
            } catch (JSONException e) {
                // 获取token失败
                logger.error("获取token失败 :", e);
            }
        }
        return access_token;
    }

    public static String getAccessToken(String appid, String appsecret,Boolean newToken) {
        if (newToken) {
            logger.info("微信token主动获取");
            access_token = WeixinUtil.getAccess_token(appid, appsecret);
            time = getTime();
            return access_token;
        }
        if (access_token == null) {
            logger.info("微信token为空获取");
            access_token = WeixinUtil.getAccess_token(appid, appsecret);
            time = getTime();
        } else {
            logger.info("微信token不为空获取旧的");
            if (!time.substring(0, 13).equals(getTime().substring(0, 13))) { // 每小时刷新一次
                logger.info("微信token过期重新获取新的");
                access_token = null;
                access_token = getAccess_token(appid, appsecret);
                time = getTime();
            }
        }
        return access_token;
    }

    /**
     * 调用微信JS接口的临时票据
     *
     * @param access_token
     *            接口访问凭证
     * @return
     */
    private static String getJsApiTicket(String access_token) {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
        String requestUrl = url.replace("ACCESS_TOKEN", access_token);
        // 发起GET请求获取凭证
        JSONObject jsonObject = httpsRequest(requestUrl);
        String ticket = null;
        if (null != jsonObject) {
            try {
                ticket = jsonObject.getString("ticket");
            } catch (JSONException e) {
                // 获取token失败
                logger.error("获取token失败 :", e);
            }
        }
        return ticket;
    }

    /**
     *
     * @param appId
     *            公账号appId
     * @param appSecret
     * @param appId
     *            当前网页的URL，不包含#及其后面部分
     * @return
     */
    public static Map<String, String> getParam(String appId, String appSecret, HttpServletRequest request) {
        if (access_token == null) {
            access_token = getAccess_token(appId, appSecret);
            jsapi_ticket = getJsApiTicket(access_token);
            time = getTime();
        } else {
            if (!time.substring(0, 13).equals(getTime().substring(0, 13))) { // 每小时刷新一次
                access_token = null;
                access_token = getAccess_token(appId, appSecret);
                jsapi_ticket = getJsApiTicket(access_token);
                time = getTime();
            }
        }
        String url = getUrl(request);
        Map<String, String> params = sign(jsapi_ticket, url);
        params.put("appid", appId);
        return params;
    }

    public static Map<String, String> getCustomerInfo(String appId, String appSecret, HttpServletRequest request) {
        if (access_token == null) {
            access_token = getAccess_token(appId, appSecret);
            customer_info = getCustomerInfo(access_token);
            time = getTime();
        } else {
            if (!time.substring(0, 13).equals(getTime().substring(0, 13))) { // 每小时刷新一次
                access_token = null;
                access_token = getAccess_token(appId, appSecret);
                customer_info = getCustomerInfo(access_token);
                time = getTime();
            }
        }
        String url = getUrl(request);
        Map<String, String> params = sign(customer_info, url);
        params.put("appid", appId);
        return params;
    }

    private static String getUrl(HttpServletRequest request) {
        StringBuffer requestUrl = request.getRequestURL();
        String queryString = request.getQueryString();
        String url = requestUrl + "?" + queryString;
        // 原始的url默认80端口，request.getRequestURL()会带有tomcat端口，一定要去掉，否则签名会验证失败
        url = url.replaceFirst(":\\d{4}", "");
        return url;
    }

    public static Map<String, String> sign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String str;
        String signature = "";

        // 注意这里参数名必须全部小写，且必须有序
        str = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;

        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(str.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);
        return ret;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    // 获取当前系统时间 用来判断access_token是否过期
    public static String getTime() {
        Date dt = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(dt);
    }

    private static JSONObject httpsRequest(String url) {
        HttpClient httpclient = new HttpClient();
        GetMethod getMethod = null;
        try {
            getMethod = new GetMethod(url);
            int code = httpclient.executeMethod(getMethod);
            if (code == 200) {
                String ret = getMethod.getResponseBodyAsString();
                return JSONObject.parseObject(ret);
            } else {
                logger.info("连接微信服务器失败");
            }
        } catch (Exception e) {
            logger.error("httpsRequest error:", e);
        } finally {
            if (getMethod != null) {
                getMethod.releaseConnection();
            }
        }
        return new JSONObject();
    }

    /**
     * 获取客服基本信息
     *
     * @param access_token
     *            接口访问凭证
     * @return
     */
    private static String getCustomerInfo(String access_token) {
        String url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN";
        String requestUrl = url.replace("ACCESS_TOKEN", access_token);
        // 发起GET请求获取凭证
        JSONObject jsonObject = httpsRequest(requestUrl);
        String ticket = null;
        if (null != jsonObject) {
            try {
                ticket = jsonObject.getString("ticket");
            } catch (JSONException e) {
                // 获取token失败
                logger.error("获取token失败 :", e);
            }
        }
        return ticket;
    }

    /**
     * 获取客户基本信息， nickname
     *
     * @param ACCESS_TOKEN
     * @param OPENID
     * @return
     * @throws UnsupportedEncodingException
     */
    public static JSONObject getWeixinUserInfo(String ACCESS_TOKEN, String OPENID) throws UnsupportedEncodingException {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        String requestUrl = url.replace("ACCESS_TOKEN", ACCESS_TOKEN).replace("OPENID", OPENID);
        // 发起GET请求获取凭证
        return httpsRequest(requestUrl);
    }

    public static Map fetchOpenidFromWX(String code, String appId, String appKey) {
        String openid = "";
        String urlRet = HttpClientUtils.httpsRequest(com.ticket.common.constant.Constants.OAUTH2_URL.replace("APPID", appId)
                .replace("SECRET", appKey).replace("CODE", code), "GET", null);
        logger.info("===============urlRet : " + urlRet + "code--------------------->" + code);
        return JSONObject.parseObject(urlRet);
    }
    
    
}
